Release 10.1A: OpenEdge Development:
Progress 4GL Handbook
Generating a procedure listing file
To verify how Progress is scoping the record buffers, you can generate a listing file that contains various information about how Progress processes the procedure when you compile or run it.
![]()
To do this, use the
LISTINGoption on theCOMPILEstatement:
- Save the procedure so that it has a name you can reference:
testscope.p.- Open another procedure window and enter this statement:
- Press F2 to run the
COMPILEstatement.- Select File
Open to open
testscope.lis. Here is the code you should see:
This listing file tells you that line 1 of the procedure starts a
FORblock and that this block does not start a transaction (again, more on that in Chapter 16 "Updating Your Database and Writing Triggers"). The next line tells you what you need to know about scoping. The line that readsBuffers: sports2000.Customertells you that the Customer buffer is scoped to thisFORblock and that it used an unnamed frame that is also scoped to that block. Next you see that anotherFORblock begins at line 7. The Customer buffer is also (independently) scoped to that block and it has its own unnamed frame.You could construct similar examples using any combination of strong- and weak-scoped buffer references. For example, here’s a variation on the test procedure that uses a
DO FORblock with a strong scope to the Customer buffer:
This procedure scopes the Customer buffer to each block in turn, just as the first example does.
Record Buffer Rule 2: You cannot nest two weak-scoped references to the same buffer.
For example, here’s a procedure that violates this rule:
If you try to run this procedure, you get the error shown in Figure 7–3 that tells you that your buffer references are invalid.
Figure 7–3: Invalid buffer references error message
![]()
When you think about it, this is perfectly sensible and necessary. Picture this situation:
Progress is using the Customer buffer for the current Customer record in the outer
FOR EACHblock. The first time through the block, it contains the New Hampshire Customer with the highest CreditLimit. Now suddenly Progress gets a request to use that same buffer to start anotherFOR EACHblock, while it’s still in the middle of processing the outer one. This could not possibly work. If Progress replaced the New Hampshire Customer with whatever Customer was the first one to satisfy the selection of Customers with higher CreditLimits and then you had another reference to the first Customer later on in the outer block (which would be perfectly valid), that Customer record would no longer be available because Progress would have used the same buffer for the innerFOR EACHblock. Because this can’t be made to work with both blocks sharing the same buffer at the same time, this construct is invalid.Record Buffer Rule 3: A weak-scope block cannot contain any free references to the same buffer.
This rule makes sense for the same reasons as the second rule. Consider this example:
While Progress is processing the
FOR EACHblock, it gets a request to use the same buffer to find a completely unrelated record. This fails with a similar error, as shown in Figure 7–4.Figure 7–4: FOR EACH processing error message
![]()
Record Buffer Rule 4: If you have a free reference to a buffer, Progress tries to scope that buffer to the nearest enclosing block with record scoping properties (that is, a FOR EACH block, a DO FOR block, or a REPEAT block). If no block within the procedure has record scoping properties, then Progress scopes the record to the entire procedure.
This rule also makes good sense when you think about it. The
FINDstatements are called free references because they don’t define a scope for the buffer, they just reference it. Therefore, Progress has to identify some scope for the record beyond theFINDstatement. When a block has record scoping properties, it is a block Progress might try to scope a record to, when the record is referenced inside the block.Here’s another variation on the
testscope.pprocedure that demonstrates this rule:
This procedure is perfectly valid. The first time through the
FOR EACHloop, the procedure saves off the CreditLimit for use later in the procedure. Because thedLimitvariable is initialized to zero, checking fordLimit = 0tells you whether it’s already been set. When you run it, you see all the New Hampshire Customer records followed by the first Customer with a CreditLimit higher than the highest value for New Hampshire Customers. Because there’s no conflict with two blocks trying to use the same buffer at the same time, it compiles and runs successfully.But the rule that Progress raises the scope in this situation is a critically important one. In complex procedures, the combination of buffer references you use might force Progress to scope a record buffer higher in the procedure than you expect. Though this normally does not have a visible effect when you’re just reading records, when you get to the discussion of transactions this rule becomes much more important. If you generate another listing file for this procedure, you see the effect of the
FINDstatement:
This tells you that the Customer buffer is scoped at line 0, that is, to the procedure itself. There’s no reference to the Customer buffer in the information for the
FORblock at line 3 because Progress has already scoped the buffer higher than that block.Next is the rule concerning combining
FINDstatements with strong-scoped, rather than weak-scoped references.Record Buffer Rule 5: If you have a strong-scoped reference to a buffer, you cannot have a free reference that raises the scope to any containing block.
This rule also makes perfect sense. The whole point of using a strong-scoping form, such as a
DO FORblock, is to force the buffer scope to that block and nowhere else. If Progress encounters some other statement (such as aFINDstatement) outside the strong-scoped block that forces it to try to scope the buffer higher than the strong scope, it cannot do this because this violates the strong-scoped reference. Here’s an example:
If you try to run this procedure you get the error shown in Figure 7–5.
Figure 7–5: Conflicting table reference error message
![]()
Remember this distinction between Rule 1 and Rule 5. Rule 1 says that strong- and weak-scoped references in separate blocks are self-contained, so it is legal to have multiple blocks in a procedure that scope the same buffer to the block. Rule 5 tells you that it is not legal to have some other reference to the buffer that would force the scope to be higher than any of the strong-scoped references to it.
Here are a few more small examples that illustrate how these rules interact:
This procedure displays all the Customers with CreditLimits over 80000, saving off the Customer number of the highest one. Figure 7–6 shows the first result.
Figure 7–6: Customers with CreditLimits over 80000 – first result
![]()
It then finds that Customer again with the highest CreditLimit and redisplays it with some more fields, as shown in Figure 7–7.
Figure 7–7: Customers with CreditLimits over 80000 – next result
![]()
This example illustrates that it is valid to have a weak-scoped block enclosed in a strong-scoped block. Progress raises the scope of the Customer buffer to the outer
DO FORblock. This allows you to reference the buffer elsewhere in theDO FORblock, such as theFINDstatement. TheFINDstatement raises the scope of the buffer to theDO FORblock, the nearest containing block with block-scoping properties.Here’s another example that illustrates raising buffer scope:
As it processes the procedure, Progress encounters the
FINDstatement and tentatively scopes the Customer buffer to theREPEATblock. TheREPEATblock by itself does not force a buffer scope without aFORphrase attached to it but it does have the record-scoping property, so it is the nearest containing block for theFINDstatement. This block cycles through Customers in Name order and leaves the block when it gets to the first one starting with D. But after that block ends, Progress finds a free reference to the Customer buffer in theDISPLAYstatement. This forces Progress to raise the scope of the buffer outside theREPEATblock. Since there is no available enclosing block to scope the buffer to, Progress scopes it to the procedure. Thus, the Customer buffer from theREPEATblock is available after that block ends to display fields from the record, as shown in Figure 7–8.Figure 7–8: Raising buffer scope example result
![]()
This next procedure has two free references, each within its own
REPEATblock:
As before, Progress initially scopes the buffer to the first
REPEATblock. But on encountering anotherFINDstatement within anotherREPEATblock, Progress must raise the scope to the entire procedure. The first block cycles through Customers until it finds and displays the first one whose name begins with D, and then leaves the block. Because the buffer is scoped to the entire procedure, theFINDstatement inside the secondREPEATblock starts up where the first one ended, and continues reading Customers until it gets to the first one beginning with E. Figure 7–9 shows the result.Figure 7–9: Raising buffer scope example 2 result
![]()
This is a very important aspect of buffer scoping. Not only are both blocks using the same buffer, they are also using the same index cursor on that buffer. This is different from the earlier examples where multiple strong- or weak-scoped blocks scope the buffer independently. In these cases, each block uses a separate index cursor, so a second
DO FORorFOR EACHstarts fresh back at the beginning of the record set. The difference is that theFINDstatements inside theseREPEATblocks are free references, so they force Progress to go up to an enclosing block that encompasses all the free references.
|
Copyright © 2005 Progress Software Corporation www.progress.com Voice: (781) 280-4000 Fax: (781) 280-4095 |